package proxy

import (
	"npxy-go/pkg/tcp"
	"sync"
	"sync/atomic"
)

type SessionManager struct {
	sessionIdMap *sync.Map
	idSessionMap *sync.Map
	sessionIdInc int32
}

func NewSessionManager() *SessionManager {
	return &SessionManager{
		sessionIdMap: new(sync.Map),
		idSessionMap: new(sync.Map),
	}
}

func (s *SessionManager) Save(ses *tcp.Session) int32 {
	id := atomic.AddInt32(&s.sessionIdInc, 1)
	s.PutSession(id, ses)
	return id
}

func (s *SessionManager) PutSession(id int32, ses *tcp.Session) {
	s.idSessionMap.Store(id, ses)
	s.sessionIdMap.Store(ses, id)
}

func (s *SessionManager) Release(ses *tcp.Session) {
	s.doDelete(ses, s.SessionId(ses))
}

func (s *SessionManager) ReleaseById(id int32) {
	s.doDelete(s.GetSession(id), id)
}

func (s *SessionManager) GetSession(id int32) *tcp.Session {
	if ses, ok := s.idSessionMap.Load(id); ok {
		return ses.(*tcp.Session)
	}

	return nil
}

func (s *SessionManager) SessionId(ses *tcp.Session) int32 {
	if id, ok := s.sessionIdMap.Load(ses); ok {
		return id.(int32)
	}

	return 0
}

func (s *SessionManager) doDelete(ses *tcp.Session, id int32) {
	s.idSessionMap.Delete(id)
	s.idSessionMap.Delete(ses)

	if ses != nil {
		ses.Close()
	}
}

func (s *SessionManager) ClearAll() {
	s.sessionIdMap.Range(func(key, value interface{}) bool {
		s.idSessionMap.Delete(key)
		return true
	})

	s.idSessionMap.Range(func(key, value interface{}) bool {
		value.(*tcp.Session).Close()
		s.idSessionMap.Delete(key)
		return true
	})
}

func (s *SessionManager) Send(id int32, buf *tcp.Buffer) {
	ses := s.GetSession(id)
	if ses != nil {
		ses.Send(buf)
	}
}
